package com.tianji.promotion.service.impl;

import com.alibaba.nacos.api.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.cache.CategoryCache;
import com.tianji.common.domain.dto.PageDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.CollUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.promotion.domain.dto.CouponFormDTO;
import com.tianji.promotion.domain.dto.CouponIssueFormDTO;
import com.tianji.promotion.domain.po.Coupon;
import com.tianji.promotion.domain.po.CouponScope;
import com.tianji.promotion.domain.po.UserCoupon;
import com.tianji.promotion.domain.query.CouponQuery;
import com.tianji.promotion.domain.vo.CouponDetailVO;
import com.tianji.promotion.domain.vo.CouponPageVO;
import com.tianji.promotion.domain.vo.CouponScopeVO;
import com.tianji.promotion.domain.vo.CouponVO;
import com.tianji.promotion.enums.ObtainType;
import com.tianji.promotion.mapper.CouponMapper;
import com.tianji.promotion.service.ICouponScopeService;
import com.tianji.promotion.service.ICouponService;
import com.tianji.promotion.service.IExchangeCodeService;
import com.tianji.promotion.service.IUserCouponService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 优惠券的规则信息 服务实现类
 * </p>
 *
 * @author xjs
 */
@Service
public class CouponServiceImpl extends ServiceImpl<CouponMapper, Coupon> implements ICouponService {

    @Autowired
    private ICouponScopeService scopeService;

    @Autowired
    private IExchangeCodeService exchangeCodeService;

    @Autowired
    private CategoryCache categoryCache;

    @Autowired
    private IUserCouponService userCouponService;


    @Override
    @Transactional
    public void saveCoupon(CouponFormDTO dto) {
        // 保存到coupon
        Coupon coupon = BeanUtils.copyBean(dto, Coupon.class);
        this.save(coupon);
        // 判断是否有作用范围
        Boolean specific = dto.getSpecific();
        // 如果没有作用范围，结束
        if(specific != null && !specific){
            return;
        }
        // 有范围
        List<Long> scopes = dto.getScopes();
        // 保存coupon_scope
        scopeService.saveCouponScope(coupon, scopes);
    }

    @Override
    public PageDTO<CouponPageVO> queryCouponByPage(CouponQuery dto) {
        LambdaQueryWrapper<Coupon> queryWrapper = new LambdaQueryWrapper<>();
        // 设置查询条件
        queryWrapper.eq(dto.getType()!=null, Coupon::getType, dto.getType());
        queryWrapper.eq(dto.getStatus()!=null, Coupon::getStatus, dto.getStatus());
        queryWrapper.like(!StringUtils.isBlank(dto.getName()), Coupon::getName, dto.getName());
        // 设置排序
        queryWrapper.orderByDesc(Coupon::getCreateTime);
        // 设置分页
        Page<Coupon> ipage = new Page<>(dto.getPageNo(), dto.getPageSize());
        // 分页查询
        List<Coupon> records = this.page(ipage, queryWrapper).getRecords();
        if(CollUtils.isEmpty(records)){
            return PageDTO.empty(ipage);
        }
        // po->vo拼装返回
        List<CouponPageVO> voList = BeanUtils.copyList(records, CouponPageVO.class);
        return PageDTO.of(ipage, voList);
    }

    @Override
    public void beginIssue(CouponIssueFormDTO dto) {
        // 根据id查询优惠券
        Coupon coupon = this.getById(dto.getId());
        if(coupon == null){
            throw new BizIllegalException("优惠券为空");
        }
        // 更新coupon, 发放时间、领用时间
        Coupon update = BeanUtils.copyBean(dto, Coupon.class);
        // 根据开始发放时间，设置status
        if(dto.getIssueBeginTime() == null || dto.getIssueBeginTime().isBefore(LocalDateTime.now())){
            // 说明是立即发放
            update.setIssueBeginTime(LocalDateTime.now());
            update.setStatus(3);
        }else{
            //说明将来发放
            update.setStatus(2);
            // TODO  创建延迟任务
        }
        // 更新优惠券
        this.updateById(update);
        // 判断领用方式，如果是兑换码，并且不能是生成过，异步生成兑换码，CodeUtil
        if(coupon.getObtainWay() != null && (coupon.getObtainWay() == ObtainType.ISSUE) && coupon.getStatus() == 1){
            coupon.setIssueEndTime(dto.getIssueEndTime());
            exchangeCodeService.asyncGenerateExchangeCode(coupon);
        }
    }

    @Override
    public CouponDetailVO queryCouponById(Long id) {
        // 1.查询优惠券
        Coupon coupon = getById(id);
        // 2.转换VO
        CouponDetailVO vo = BeanUtils.copyBean(coupon, CouponDetailVO.class);
        if (vo == null || !coupon.getSpecific()) {
            // 数据不存在，或者没有限定范围，直接结束
            return vo;
        }
        // 3.查询限定范围
        List<CouponScope> scopes = scopeService.lambdaQuery().eq(CouponScope::getCouponId, id).list();
        if (CollUtils.isEmpty(scopes)) {
            return vo;
        }
        List<CouponScopeVO> scopeVOS = scopes.stream()
                .map(CouponScope::getBizId)
                .map(cateId -> new CouponScopeVO(cateId, categoryCache.getNameByLv3Id(cateId)))
                .collect(Collectors.toList());
        vo.setScopes(scopeVOS);
        return vo;
    }

    @Override
    public List<CouponVO> queryIssuingCoupons() {
        Long userId = UserContext.getUser();
        // coupon表 ： 发放中 && 非兑换
        LambdaQueryWrapper<Coupon> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Coupon::getStatus, 3);
        queryWrapper.eq(Coupon::getObtainWay, ObtainType.PUBLIC);
        List<Coupon> couponList = this.list(queryWrapper);
        if(CollUtils.isEmpty(couponList)){
            return null;
        }

        List<Long> couponIds = couponList.stream().map(Coupon::getId).distinct().collect(Collectors.toList());
        // 查询用户领过的优惠券
        List<UserCoupon> userCoupons = userCouponService.lambdaQuery().eq(UserCoupon::getUserId, userId).in(UserCoupon::getCouponId, couponIds).list();
        Map<Long, Long> userCouponCountMap = new HashMap<>();
        Map<Long, Long> unusedCouponCountMap = new HashMap<>();
        if(!CollUtils.isEmpty(userCoupons)){
            userCouponCountMap = userCoupons.stream().collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));
            unusedCouponCountMap = userCoupons.stream().filter(uc-> Objects.equals(uc.getStatus(), 1))
                    .collect(Collectors.groupingBy(UserCoupon::getCouponId, Collectors.counting()));
        }
        //封装查询结果
        List<CouponVO> voList = new ArrayList<>(couponList.size());
        for (Coupon coupon : couponList) {
            CouponVO vo = BeanUtils.copyBean(coupon, CouponVO.class);
            //  是否可以领取
            // coupon表的 是否有剩余：total_num > issue_num
            // coupon表的 用户限领user_limit > user_coupon表的用户已经领数量
            Long userCouponCount = userCouponCountMap.getOrDefault(coupon.getId(), 0L);
            boolean available = (coupon.getTotalNum() > coupon.getIssueNum())&&(coupon.getUserLimit() > userCouponCount);
            vo.setAvailable(available);
            // 是否可以使用
            // user_coupon有未使用的记录
            Long unusedCount = unusedCouponCountMap.getOrDefault(coupon.getId(), 0L);
            boolean received = unusedCount > 0;
            vo.setReceived(received);
            voList.add(vo);
        }
        return voList;
    }

    @Override
    public int incrementIssuneNum(Long couponId) {
        return this.baseMapper.incrementIssuneNum(couponId);
    }
}
